#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>

#include "mylib_parse.h"
#include "wbdl.h"
#include "os.h"
#include "pcre2lib.h"

enum parse_state {
	STATE_LEVEL2 = 0,
	STATE_LEVEL3,
	STATE_MERMAID,
	STTE_LEVEL_END
};

FILE* gfp_md = NULL;
const char test_url[] = "https://deepwiki.com/sonertari/SSLproxy";

char hmtl_content[MAX_BUF_LEN];
char html2_content[MAX_BUF_LEN];

char url_root[512];

static void regex_replace_char(char* buf, char* match, char* replace, char* result)
{
	regex_replace(buf, (unsigned int)strlen(buf), match, replace, result, MAX_BUF_LEN, 0);
}

char* skip_space(char* buf)
{
	while (*buf) {
		if (*buf == ' ')
			buf++;
		else
			break;
	}
	return buf;
}

char* skip_crlf(char* buf)
{
	while (*buf) {
		if (!memcmp(buf, "\\n", 2)) {
			buf = buf + 2;
		}
		else
			break;
	}
	return buf;
}

char* goto_line_end(char* buf)
{
	while (*buf) {
		if (memcmp(buf, "\\n", 2))
			buf++;
		else
			break;
	}
	return buf;
}

int get_crlf_counts(char* buf)
{
	int cnt = 0;
	char* head = buf;
	while (*head) {
		if (!memcmp(head, "\\n", 2)) {
			head = head + 2;
			cnt++;
		}
		else {
			break;
		}
	}
	return cnt;
}

void write_content_line(char* buf)
{
	if (!*buf)
		return;

	//\\n to \n
	regex_replace_char(buf, "\\\\n", "\n", html2_content);

	//\u003e to >
	regex_replace_char(html2_content, "\\\\u003e?", ">", buf);

	//\u0026 to &
	regex_replace_char(buf, "\\\\u0026?", "&", html2_content);

	//\u003c to <
	regex_replace_char(html2_content, "\\\\u003c?", "<", buf);

	//\" to "
	regex_replace_char(buf, "\\\\", "", html2_content);

	//write to file
	fprintf(gfp_md, "%s\n\n", html2_content);
}

/*
"# Overview\n\n\u003cdetails\u003e\n

\n\n\u003cdetails\u003e\n\u003csummary\u003eRelevant source files\u003c/summary\u003e\n\n
<details> 
<summary>Relevant source files</summary>
...
</details>
\u003c/details\u003e\n\n\n\n
*/
char* write_detail_section(char* buf)
{
	char* head;
	char* tail;
	head = buf;
	tail = strstr(head, "\\n");
	if (!tail)
		return NULL;
	*tail = 0;
	//title of this chapter
	fprintf(gfp_md, "#%s\n", head);
	*tail = '\\';

	//goto <details>
	int crlf_cnt;
	crlf_cnt = get_crlf_counts(tail);
	head = tail + crlf_cnt * 2;
	if (memcmp(head, "\\u003cdetails\\u003e", strlen("\\u003cdetails\\u003e")))
		return NULL;
	//reach to <details>
	//\u003cdetails\u003e\n\u003csummary\u003eRelevant source files\u003c/summary\u003e\n\n
	head = skip_crlf(head);
	fprintf(gfp_md, "## Relevant source files\n");
	head = goto_line_end(head);
	head = skip_crlf(head);

	head = goto_line_end(head);
	head = skip_crlf(head);

	while (1) {
		tail = goto_line_end(head);
		*tail = 0;
		fprintf(gfp_md, "%s\n", head);
		*tail = '\\';
		head = skip_crlf(tail);
		if (!memcmp(head, "\\u003c/details\\u003e", strlen("\\u003c/details\\u003e")))
			break;
	}
	fprintf(gfp_md, "\n\n");
	head = goto_line_end(head);
	head = skip_crlf(head);
	return head;
}

/*
## System Architecture Overview: STATE_LEVEL2
### High-level Architecture Diagram: STATE_LEVEL3
```mermaid" : STATE_MERMAID
*/
char* find_next_symbol(char* buf, enum parse_state* pstate)
{
	enum parse_state state = STTE_LEVEL_END;
	*pstate = STTE_LEVEL_END;

	char* head = buf;
	while (*head) {
		if (!memcmp(head, "## ", 3)) {
			state = STATE_LEVEL2;
			break;
		}

		if (!memcmp(head, "### ", 4)) {
			state = STATE_LEVEL3;
			break;
		}

		if (!memcmp(head, "```mermaid", strlen("```mermaid"))) {
			state = STATE_MERMAID;
			break;
		}
		head++;
	}

	*pstate = state;
	return head;
}

/*
* angle brackets: AB < >
* double quotation marks: DQM "
*/
enum mermaid_state {
	MERMAID_START = 0, //```mermaid
	MERMAID_RAB, // \u003e >
	MERMAID_LAB, // \u003c <
	MERMAID_DQM, // \"
	MERMAID_LINE_STOP, // \n
	MERMAID_PARTICI, //participant
	MERMAID_AND, //\u0026 &
	MERMAID_STOP, //```
	MERMAID_END
};


char* find_mermaid_symbol(char* buf, enum mermaid_state* pstate)
{
	char* head = buf;
	enum mermaid_state state = MERMAID_END;
	*pstate = MERMAID_END;

	while (*head) {
		if (!memcmp(head, "```mermaid", strlen("```mermaid"))) {
			state = MERMAID_START;
			break;
		}

		if (!memcmp(head, "\\n", 2)) {
			state = MERMAID_LINE_STOP;
			break;
		}

		if (!memcmp(head, "participant", strlen("participant"))) {
			state = MERMAID_PARTICI;
			break;
		}

		if (!memcmp(head, "\\u0026", 6)) {
			state = MERMAID_AND;
			break;
		}

		if (!memcmp(head, "\\u003e", 6)) {
			state = MERMAID_RAB;
			break;
		}

		if (!memcmp(head, "\\u003c", 6)) {
			state = MERMAID_LAB;
			break;
		}

		if (!memcmp(head, "\\\"", 2)) {
			state = MERMAID_DQM;
			break;
		}

		if (!memcmp(head, "```", 3)) {
			state = MERMAID_STOP;
			break;
		}
		head++;
	}

	*pstate = state;
	return head;
}

/*
```mermaid\n
graph TD\n
Client[\"Client\"] --\u003e|\"Encrypted Connection\"| NAT[\"NAT Engine\"]\n
NAT --\u003e|\"Redirected Traffic\"| Core[\"Core Proxy System\"]\n    \n

subgraph \"SSLproxy\"\n
Core --\u003e|\"Configures\"| Config[\"Configuration System\"]\n
Core --\u003e|\"Uses\"| SSL[\"SSL/TLS Handler\"]\n
Core --\u003e|\"Records\"| Logging[\"Logging System\"]\n
Core --\u003e|\"Enforces\"| Filter[\"Filtering System\"]\n
Core --\u003e|\"Secures\"| PrivSep[\"Privilege Separation\"]\n        \n
Config --\u003e|\"Controls\"| Filter\n
SSL --\u003e|\"Certificate Ops\"| CertMgmt[\"Certificate Management\"]\n
end\n    \n

Core --\u003e|\"Divert Mode\"| Program[\"Listening Program\"]\n
Core --\u003e|\"Split/Pass Mode\"| Server[\"Original Server\"]\n
```\n\n
*/

//return next word pointer
char* get_participant_word(char* buf, char* word)
{
	char* head;
	char* tail;
	char* next = NULL;

	head = skip_space(buf);
	tail = head;
	while (*tail) {
		if (*tail == ' ') {
			*tail = 0;
			strcpy(word, head);
			*tail = ' ';
			next = tail;
			break;
		}

		//\"
		if (!memcmp(tail, "\\\"", 2)) {
			head = tail + 2;
			tail = strstr(head, "\\\"");
			*tail = 0;
			strcpy(word, head);
			*tail = '\\';
			next = tail + 2;
			break;
		}

		//\n
		if (!memcmp(tail, "\\\n", 2)) {
			*tail = 0;
			strcpy(word, head);
			*tail = '\\';
			next = tail + 2;
			break;
		}

		tail++;
	}

	if (!*tail) {
		//last word
		strcpy(word, head);
	}
	return next;
}
/*
participant \"Client\" as C\n
->
participant C as Client

participant Source as \"Source Connection\"\n
->
participant Source as Source Connection

participant NAT as \"NAT Engine\"\n
*/
char* participant_handler(char* buf)
{
	char* head = buf;
	char* line_end = strstr(head, "\\n");
	*line_end = 0;

	static char words[4][256];
	int as_index = 0;
	int cnt = 0;
	while (head) {
		head = get_participant_word(head, words[cnt]);
		if (!strcmp(words[cnt], "as")) {
			//participant Client as C -> participant C as Client
			as_index = cnt;
		}
		cnt++;
	}

	if (as_index) {
		//participant C as Client
		//participant Listener as proxy_listener_acceptcb
		//participant NAT as "NAT Engine"\n
		//short word as long word
		size_t a, b;
		a = strlen(words[as_index - 1]);
		b = strlen(words[as_index + 1]);
		if(a < b)
			fprintf(gfp_md, "    participant %s as %s\n", words[as_index - 1], words[as_index + 1]);
		else
			fprintf(gfp_md, "    participant %s as %s\n", words[as_index + 1], words[as_index - 1]);
	} else {
		//participant SSLproxy
		fprintf(gfp_md, "    participant %s\n", words[1]);
	}
	head = line_end + 2;
	*line_end = '\\';
	return head;
}

//return next line
char* write_mermaid_line(char* line, enum mermaid_state state)
{
	char* head = line;
	char* tail = line;

	switch (state) {
	case MERMAID_START:
	case MERMAID_LINE_STOP:
		tail = goto_line_end(head);
		*tail = 0;
		fprintf(gfp_md, "%s\n", head);
		*tail = '\\';
		head = tail + 2;
		break;
	case MERMAID_RAB:
		tail = strstr(head, "\\u003e");
		*tail = 0;
		fprintf(gfp_md, "%s>", head);
		*tail = '\\';
		head = tail + strlen("\\u003e");
		if (!memcmp(head, "\\u003e", strlen("\\u003e"))) {
			fprintf(gfp_md, ">");
			head = head + strlen("\\u003e");
		}
		break;

	case MERMAID_LAB:
		tail = strstr(head, "\\u003c");
		*tail = 0;
		fprintf(gfp_md, "%s<", head);
		*tail = '\\';
		head = tail + strlen("\\u003c");
		break;
	case MERMAID_AND:
		tail = strstr(head, "\\u0026");
		*tail = 0;
		fprintf(gfp_md, "%s&", head);
		*tail = '\\';
		head = tail + strlen("\\u0026");
		break;
	case MERMAID_DQM:
		tail = strstr(head, "\\\"");
		*tail = 0;
		fprintf(gfp_md, "%s\"", head);
		*tail = '\\';
		head = tail + 2;
		break;
	case MERMAID_PARTICI:
		//participant "Client" as C -> participant C as Client
		head = participant_handler(head);
		break;
	case MERMAID_STOP:
		fprintf(gfp_md, "```\n\n");
		head = skip_crlf(head + 3);
		break;
	default:
		break;
	}

	return head;
}

char* write_mermaid(char* buf)
{
	char* head;
	
	enum mermaid_state state = MERMAID_START;
	head = buf;
	while (state != MERMAID_STOP) {
		find_mermaid_symbol(head, &state);
		head = write_mermaid_line(head, state);
	}

	return head;
}

void record_it(char* buf)
{
	char* head;
	char* tail;

	//<detail> ... </detail>
	head = write_detail_section(buf);
	if (!head)
		return;

	//## ...
	tail = strstr(head, "##");
	if (!tail)
		return;
	*tail = 0;
	write_content_line(head);
	*tail = '#';

	head = tail;
	//now head at ##
	enum parse_state state = STATE_LEVEL2;
	char c;
	while (state != STTE_LEVEL_END) {
		//skip ##
		tail = find_next_symbol(head + 3, &state);
		if (!tail)
			break;
		c = *tail;
		*tail = 0;
		//record it
		if (state == STATE_MERMAID) {
			write_content_line(head);
			*tail = c;

			head = write_mermaid(tail);
			//break;
			continue;
		}

		
		write_content_line(head);
		*tail = c;
		head = skip_crlf(tail);
		if (!*head)
			break;
	}

	fprintf(gfp_md, "\n\n***\n");
}

/*
 <script>
		self.__next_f.push([1,

*/
char script_head_str[] = "self.__next_f.push([1,";
void handle_script(lxb_dom_element_t* el)
{
	lxb_dom_node_t* child;
	child = lxb_dom_node_first_child(lxb_dom_interface_node(el));
	if (!child)
		return;

	lxb_char_t* text;
	size_t txt_len;
	text = lxb_dom_node_text_content(child, &txt_len);
	if (!text)
		return;

	//skip CRLF and space
	char* head = text;
	while (*head) {
		if (*head == '\n' || *head == ' ') {
			head++;
		} else {
			break;
		}
	}

	if (memcmp(head, script_head_str, strlen(script_head_str)))
		return;

	//now we cared this content
	head = head + strlen(script_head_str);
	//self.__next_f.push([1, "# Overview\n\n\u003cdetails\u003e\n
	if (memcmp(head, " \"#", 3))
		return;
	head = head + strlen(" \"#");
	record_it(head);
}

//write to gfp_md
void write_to_md(lxb_html_document_t* doc, int is_index_html)
{
	lxb_dom_element_t* element;
	lxb_char_t* str;
	size_t str_len;

	//<meta property="og:url" content="https://deepwiki.com/sonertari/SSLproxy" />
	element = find_sub_attr(lxb_dom_interface_element(doc), "meta", "property", "og:url");
	if (element && is_index_html) {
		//record root url
		
		str = (lxb_char_t*)lxb_dom_element_get_attribute(element, "content", strlen("content"), &str_len);
		if (str) {
			printf("root: %s\n", str);
			strcpy(url_root, str);
		}
	}

	size_t i, len;
	lxb_dom_collection_t* collection;
	collection = get_nodes_by_tag(lxb_dom_interface_node(doc), "script");
	if (collection) {
		len = lxb_dom_collection_length(collection);
		for (i = 0; i < len; i++) {
			element = lxb_dom_collection_element(collection, i);
			handle_script(element);
		}

		lxb_dom_collection_destroy(collection, true);
	}
}

int parse_html(char* buf, int len)
{
	lxb_html_document_t* doc;
	doc = parser_init(buf, len);
	if (!doc)
		return -1;


	lxb_char_t* value;
	size_t val_len;
	//get title
	value = (lxb_char_t*)lxb_html_document_title(doc, &val_len);
	if (value) {
		printf("start to parse chapter \"%s\"\n", value);
	}

	write_to_md(doc, 1);
	printf("\n\n");
	parse_exit(doc);
	return 0;
}

int got_html_content(char* url, char* buf, int* len)
{
	if (strstr(url, "http")) {
		return 0;
	}

	//read from local
	FILE* fp = fopen(url, "r");
	if (!fp)
		return -1;
	size_t cnt = fread(buf, 1, MAX_BUF_LEN, fp);
	if (cnt >= MAX_BUF_LEN) {
		printf("file size is larger than %d bytes\n", MAX_BUF_LEN);
	}
	fclose(fp);
	*len = (int)cnt;
	buf[cnt] = 0;

	return 0;
}

int start_downolad(char* url, int level)
{
	int ret = 0;
	int len;
	ret = got_html_content(url, hmtl_content, &len);
	if (ret) {
		return ret;
	}

	parse_html(hmtl_content, len);
	return 0;
}

int main(int argc, char** argv)
{
	char* url = (char*)test_url;
#ifdef DEBUG
	url = "index.html";
#endif

	gfp_md = fopen("1.md", "w");
	start_downolad(url, 0);
	fclose(gfp_md);
	return 0;
}